package pvn.com;

import pvn.com.interfaces.IObjectMessageListener;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Date;
import java.util.Vector;
import javax.microedition.io.SocketConnection;
import javax.microedition.io.StreamConnection;
import net.rim.device.api.i18n.ResourceBundle;
import net.rim.device.api.io.SocketConnectionEnhanced;
import net.rim.device.api.io.transport.ConnectionDescriptor;
import net.rim.device.api.io.transport.ConnectionFactory;
import net.rim.device.api.ui.UiApplication;

public class ServerConnection
  implements Runnable
{
  ResourceBundle _res;
  private ServerConnection me;
  private IObjectMessageListener m_ui;
  private Thread thread;
  private String m_ip;
  private int m_port;
//  private ConnectionQueue queue = null;
  private Thread queue_thread;
  private StreamConnection conn;
  public String lastErrorDesc = "";
  private Vector CommandsToSend = new Vector();
  private boolean shouldStop = false;
  char[] ReadBuffer = null;
  public boolean sendConnected = true;
  public boolean sendErrors = true;

  public ServerConnection(IObjectMessageListener _ui, ResourceBundle res)
  {
    this.m_ui = _ui;
    this.me = this;
   // this.queue = new ConnectionQueue(_ui, this);
    this.ReadBuffer = new char[1024];
    this._res = res;
  }

  public void Connect(String ip, int port) {
    this.m_ip = ip;
    this.m_port = port;

   // this.queue_thread = new Thread(this.queue);
    this.queue_thread.start();

    this.thread = new Thread(this);
    this.thread.start();
  }

  public synchronized void Disconnect()
  {
    this.shouldStop = true;
    try
    {
    //  if (this.queue != null)
     //   this.queue.stop();
    }
    catch (Exception localException)
    {
    }
    Date dt = new Date();
    if (this.thread != null)
    {
      while ((this.thread.isAlive()) && (new Date().getTime() - dt.getTime() < 5000L))
      {
        try
        {
          Thread.sleep(100L);
        }
        catch (InterruptedException localInterruptedException)
        {
        }

      }

    }

    try
    {
      if (this.queue_thread.isAlive())
        this.queue_thread.interrupt();
    }
    catch (Exception localException1)
    {
    }
    try
    {
      if (this.thread.isAlive())
        this.thread.interrupt();
    }
    catch (Exception localException2)
    {
    }
   // this.queue = null;
    this.queue_thread = null;
    this.thread = null;
  }

  public void run()
  {
    String URL = "socket://" + this.m_ip + ":" + this.m_port;

  //  int[] preferredTransportTypes = ParamsStorage.settings.getPreferredTransports();

    ConnectionFactory factory = new ConnectionFactory();

   // if (preferredTransportTypes != null) {
    //  factory.setPreferredTransportTypes(preferredTransportTypes);
    //}

    ConnectionDescriptor conDescriptor = null;

    conDescriptor = factory.getConnection(URL);

    if (conDescriptor == null)
    {
      HandleError(this._res.getString(11));
      return;
    }
    if (this.sendConnected) {
      SendMessage(10, 0, null);
    }
    OutputStream os = null;
    InputStream is = null;
    StringBuffer Response = new StringBuffer();
    try
    {
      this.conn = null;

      this.conn = ((StreamConnection)conDescriptor.getConnection());
      SocketConnectionEnhanced conn_ext = (SocketConnectionEnhanced)this.conn;
    //  conn_ext.setSocketOptionEx(256, 200L);
     // ((SocketConnection)conn_ext).setSocketOption(2, 2);

      os = this.conn.openOutputStream();
      is = this.conn.openInputStream();

      Date lastActivity = new Date();
      while (!this.shouldStop)
      {
        if ((this.CommandsToSend.size() == 0) && (!this.shouldStop))
        {
          Date now = new Date();
          if (now.getTime() - lastActivity.getTime() > 20000L)
          {
            String cmd = "ping$\r\n";
            os.write(cmd.getBytes());
            os.flush();
            lastActivity = new Date();
          }

        }
        else
        {
          do
          {
            String cmd = (String)this.CommandsToSend.firstElement();
            os.write(cmd.getBytes());
            os.flush();
            this.CommandsToSend.removeElement(cmd);
            lastActivity = new Date();
          }
          while ((this.CommandsToSend.size() > 0) && (!this.shouldStop));
        }

        int n = 0;
        int c = 0;
        try
        {
          do
          {
            n = is.read();
            if (n >= 0)
            {
              this.ReadBuffer[c] = (char)n;
              c++;
            }
            if ((n == -1) || (n == 10) || (c >= 1024)) break; 
          }while (!this.shouldStop);
        }
        catch (IOException e)
        {
          if (e.getMessage().compareTo("TCP receive timed out") != 0)
            throw e;
        }
        Response.append(this.ReadBuffer, 0, c);
        if ((Response.length() > 0) && (Response.charAt(Response.length() - 1) == '\n') && (!this.shouldStop))
        {
          lastActivity = new Date();
          Response.delete(Response.length() - 2, Response.length());
          if (Response.length() == 0)
            continue;
          if (Response.charAt(Response.length() - 1) != '$')
          {
            Response.delete(0, Response.length());
          }
          else {
            String cmd = Response.toString();
            ProcessResponseCommand(cmd);

            Response.delete(0, Response.length());
          }
        } else if (!this.shouldStop) {
          Thread.sleep(100L);
        }

      }

    }
    catch (InterruptedException localInterruptedException)
    {
      try
      {
        is.close(); } catch (Exception localException1) {
      }try { os.close(); } catch (Exception localException2) {
      }try { this.conn.close();
      }
      catch (Exception localException3)
      {
      }
    }
    catch (Exception e)
    {
      HandleError(e.getMessage());
      try
      {
        is.close(); } catch (Exception localException4) {
      }try { os.close(); } catch (Exception localException5) {
      }try { this.conn.close();
      }
      catch (Exception localException6)
      {
      }
    }
    finally
    {
      try
      {
        is.close(); } catch (Exception localException7) {
      }try { os.close(); } catch (Exception localException8) {
      }try { this.conn.close(); } catch (Exception localException9) {
      }
    }
  }

  private void ProcessResponseCommand(String line) {
   // this.queue.putMessage(line);
  }

  private void HandleError(String _Err)
  {
    if ((this.shouldStop) || (!this.sendErrors))
      return;
    Disconnect();
    UiApplication app = UiApplication.getUiApplication();
    this.lastErrorDesc = _Err;
    Runnable task = new Runnable()
    {
      public void run()
      {
        ServerConnection.this.m_ui.OnMsg(9, EventID.W_ERROR, ServerConnection.this.me);
      }
    };
    app.invokeLater(task);
  }

  private void SendMessage(int msg, int wparam, Object arg)
  {
    UiApplication app = UiApplication.getUiApplication();
    int msg_ = msg;
    int wparam_ = wparam;
    Object arg_ = arg;
    
    //TODO rewrite.
    
//    Runnable task = new Runnable(msg_, wparam_, arg_) { private final int val$msg_;
//      private final int val$wparam_;
//      private final Object val$arg_;
//
//      public void run() { ServerConnection.this.m_ui.OnMsg(this.val$msg_, this.val$wparam_, this.val$arg_);
//      }
//    };
    //app.invokeLater(task);
  }

  public synchronized void SendCommand(String cmd) {
    String cmdRaw = cmd + "$" + '\r' + '\n';
    this.CommandsToSend.addElement(cmdRaw);
  }

  public void SendLogin(String login, String Password) {
    String pass_md5 = Password;
    try
    {
    //  pass_md5 = md5.MD5Hash(Password);
    }
    catch (Exception localException) {
    }
    SendCommand("auth|" + login + "|" + pass_md5);
  }

  public void SendSymbolsRequest() {
    SendCommand("symbols");
  }

  public void SendSymGroupsRequest() {
    SendCommand("symgroups");
  }

  public void SendReady() {
    SendCommand("ready");
  }

  public void SendGetOpenTradesList()
  {
    SendCommand("open_trades_list");
  }

  public void SendChartRequest(String symbol, String RangeType)
  {
    SendCommand("chart|" + symbol + "|" + RangeType);
  }

  public void SendCred(String login, String Password)
  {
    String pass_md5 = Password;
    try
    {
     // pass_md5 = md5.MD5Hash(Password);
    }
    catch (Exception localException) {
    }
    SendCommand("cred_iphone|" + login + "|" + pass_md5);
  }
}